package com.personal.dataanalyse.reportmanage.base;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.Iterator;
import java.util.List;

import com.personal.core.bean.TwoTuple;
import com.personal.core.data.DataColumn;
import com.personal.core.data.DataColumns;
import com.personal.core.port.HaveDeepAndChildren;
import com.personal.core.utils.Assert;
import com.personal.core.utils.CoreUtil;
import com.personal.dataanalyse.consts.FieldConsts;
import com.personal.dataanalyse.enums.ModelFieldTypeEnum;
import com.personal.dataanalyse.enums.XyTypeEnum;
import com.personal.dataanalyse.reportmanage.entity.ConditionInfo;
import com.personal.dataanalyse.reportmanage.entity.DataColumnReportEx;
import com.personal.dataanalyse.reportmanage.entity.ReportHeader;
import com.personal.dataanalyse.reportmanage.util.ModelUtil;
import com.personal.dataconvert.bean.HeaderConfig;
import com.personal.dataconvert.util.ExcelHtmlUtil;

/**
 * 分析维度
 * @author cuibo
 *
 */
public class DimensionInfo extends AnalyseFactorInfo implements HaveDeepAndChildren
{

    /**
     * 
     */
    private static final long serialVersionUID = 1L;
    
    /** 父维度 */
    private DimensionInfo parent;
    
    /** 子维度 */
    private List<DimensionInfo> children;
    
    /** 维度的列维度指标 */
    private List<QuotaInfo> columnFields;
    
    /** 计算列 */
    private List<QuotaInfo> calFields;
    
    /** 分组名称 */
    private String groupName;
    
    /** 维度对应的字段 */
    private String groupDataSql;
    
    /** 该维度所在的深度 */
    private int deepLength;
    
    /** 是否是常量的维度 */
    private boolean constant;
    
    /**
     * 获取单列对应的DataColumnCollection
     * 区分普通列或者计算列, 维度 , 即Model的第一层Modelfield调用该方法。
     * @return
     * @throws Exception
     */
    public TwoTuple<DataColumns, List<ReportHeader>> getDataColumnCollection() throws Exception
    {
        // 找到下面所有的 列维度指标, 计算列，或者普通列
        TwoTuple<DataColumns, List<ReportHeader>> result = lookForCommonOrCalOrGroupField();
        calSkipCountAndWidth(result);
        return result;
    }
    
    /**
     * 递归查找X维度下的所有指标数据
     * 包括 列维度指标， 计算列指标
     * @return
     * @throws Exception 
     */
    public TwoTuple<DataColumns, List<ReportHeader>> lookForCommonOrCalOrGroupField() throws Exception
    {
        DataColumns columnResult = new DataColumns();
        List<ReportHeader> headerResult = new ArrayList<ReportHeader>();
        // 递归获取列数据
        recursionLookForCommonOrCalOrGroupField(null, columnResult, headerResult);
        // 使用此标记来判断调用该方法是生成计算列维度还是生成展示列维度（都有可能是X和Y）
        boolean removeTargetCol = this.getModel().isTransRowCol() ? XyTypeEnum.Y == this.getXy() : XyTypeEnum.X == this.getXy();
        // 计算方向的维度只需要计算列和列维度指标，其它的需要过滤
        if (removeTargetCol)
        {
            for (Iterator<DataColumn> iterator = columnResult.iterator(); iterator.hasNext();)
            {
                DataColumnReportEx columnEx = (DataColumnReportEx) iterator.next();
                if (!(ModelFieldTypeEnum.计算列.toString().equals(columnEx.getFieldType())
                        || ModelFieldTypeEnum.列维度指标.toString().equals(columnEx.getFieldType())))
                {
                    iterator.remove();
                }
            }
            // 递归移除所有的不是计算列且不是列维度指标的HeaderConfig，如果其不是计算列和列维度指标，但是其子节点有，不可移除
            ModelUtil.removeIsNotTargetHeaderConfig(headerResult);
        }
        return new TwoTuple<DataColumns, List<ReportHeader>>(columnResult, headerResult);
    }
    
    /**
     * 是否有计算列
     * @return
     */
    public boolean hasCalCol()
    {
        return calFields != null && calFields.size() > 0;
    }
    
    /**
     * 是否有列维度指标
     * @return
     */
    public boolean hasColCol()
    {
        return columnFields != null && columnFields.size() > 0;
    }
    
    /**
     * 既有计算列也有列维度指标
     * @return
     */
    public boolean hasCalAndCol()
    {
        return hasCalCol() && hasColCol();
    }
    
    /**
     * 有计算列或者有列维度指标
     * @return
     */
    public boolean hasCalOrCol()
    {
        return hasCalCol() || hasColCol(); 
    }
    
    /**
     * 父维度
     * @return
     */
    @Override
    public DimensionInfo getParent()
    {
        return parent;
    }

    /**
     * 父维度
     * @param parent
     */
    public void setParent(DimensionInfo parent)
    {
        this.parent = parent;
    }

    /**
     * 子维度集合
     * @return
     */
    @Override
    public List<DimensionInfo> getChildren()
    {
        if (children == null)
        {
            children = new ArrayList<DimensionInfo>();
        }
        return children;
    }

    /**
     * 子维度集合
     * @param children
     */
    public void setChildren(List<DimensionInfo> children)
    {
        this.children = children;
    }

    public List<QuotaInfo> getColumnFields()
    {
        return columnFields;
    }

    public void setColumnFields(List<QuotaInfo> columnFields)
    {
        this.columnFields = columnFields;
    }

    public List<QuotaInfo> getCalFields()
    {
        return calFields;
    }

    public void setCalFields(List<QuotaInfo> calFields)
    {
        this.calFields = calFields;
    }
    
    public void setXy(XyTypeEnum xy)
    {
        super.setXy(xy);
        if (this.children != null && this.children.size() > 0)
        {
            for (DimensionInfo child : this.children)
            {
                child.setXy(xy);
            }
        }
    }

    /**
     * 递归查找Y维度下的所有指标数据
     * 包括 列维度指标， 计算列指标
     * @param parent
     * @param result
     * @param headerConfigs
     * @return
     * @throws Exception 
     */
    private void recursionLookForCommonOrCalOrGroupField(DataColumnReportEx parent, DataColumns result, List<ReportHeader> headerConfigs) throws Exception
    {
        lookForXCommonOrCalOrGroupFieldImpl(parent, result, parent == null ? null : parent.getHeaderConfig(), parent == null ? headerConfigs : new ArrayList<ReportHeader>());
        // 有子维度则递归查找,虽然有返回值，但是不起作用，只是修改了result值和headerConfigs的值
        if (this.getChildren() != null && !this.getChildren().isEmpty())
        {
            // 拷贝一份，供循环使用
            DataColumns tempResult = new DataColumns();
            tempResult.addAll(result);
            // 清空原数据
            result.clear();
            DataColumns singleResult = null;
            // 当前使用的
            List<DimensionInfo> currentUse = new ArrayList<DimensionInfo>();
            currentUse.addAll(this.getChildren());
            
            // 当前维度列
            DataColumnReportEx currentGroupCol = null;
            // 当前头部
            HeaderConfig currentHeader = null;
            for (DataColumn dataColumn : tempResult)
            {
                // 要给当前维度下的计算列或者指标列和子维度排序
                DataColumnReportEx columnEx = (DataColumnReportEx) dataColumn;
                // 如果是计算列或者列维度指标则直接添加
                if (ModelFieldTypeEnum.计算列.toString().equals(columnEx.getFieldType())
                        || ModelFieldTypeEnum.列维度指标.toString().equals(columnEx.getFieldType()))
                {
                    // 如果找到了currentGroupCol从childrenTemp查找比当前小的子维度
                    if (currentGroupCol != null)
                    {
                        List<DimensionInfo> beforeList = ModelUtil.lookChildrenBefore(currentUse, columnEx.getShowOrder());
                        if (!CoreUtil.isEmpty(beforeList))
                        {
                            for (DimensionInfo child : beforeList)
                            {
                                singleResult = new DataColumns();
                                child.recursionLookForCommonOrCalOrGroupField(currentGroupCol, singleResult, headerConfigs);
                                result.addAll(singleResult);
                            }
                        }
                    }
                    HeaderConfig tempHeader = columnEx.getHeaderConfig().getParent();
                    // 如果头部值变了，全部加入，因为已经切换到另一个维度了
                    if (tempHeader != null && currentHeader != null && tempHeader != currentHeader)
                    {
                        currentHeader = tempHeader;
                        if (currentGroupCol != null && currentUse.size() > 0)
                        {
                            for (DimensionInfo child : currentUse)
                            {
                                singleResult = new DataColumns();
                                child.recursionLookForCommonOrCalOrGroupField(currentGroupCol, singleResult, headerConfigs);
                                result.addAll(singleResult);
                            }
                            // 清空
                            currentUse.clear();
                        }
                    }
                    result.add(columnEx);
                    continue;
                } else
                {
                    currentHeader = columnEx.getHeaderConfig();
                    // 如果维度值发生值变，需要把currentUse中没有使用的用完，然后在重新填充
                    if (currentGroupCol != null)
                    {
                        if (currentUse.size() > 0)
                        {
                            for (DimensionInfo child : currentUse)
                            {
                                singleResult = new DataColumns();
                                child.recursionLookForCommonOrCalOrGroupField(currentGroupCol, singleResult, headerConfigs);
                                result.addAll(singleResult);
                            }
                        }
                        // 重新填充当前user
                        currentUse.clear();
                        currentUse.addAll(this.getChildren());
                    }
                    currentGroupCol = columnEx;
                }
            }
            // 最后如果还有，则继续
            if (currentGroupCol != null && currentUse.size() > 0)
            {
                for (DimensionInfo child : currentUse)
                {
                    singleResult = new DataColumns();
                    child.recursionLookForCommonOrCalOrGroupField(currentGroupCol, singleResult, headerConfigs);
                    result.addAll(singleResult);
                }
            }
        } else 
        {
            // 使用此标记来判断调用该方法是生成计算列维度还是生成展示列维度（都有可能是X和Y）
            boolean removeTargetCol = this.getModel().isTransRowCol() ? XyTypeEnum.Y == this.getXy() : XyTypeEnum.X == this.getXy();
            if (removeTargetCol)
            {
                // 没有子节点了，就把这些都移除掉
                for (Iterator<DataColumn> iterator = result.iterator(); iterator.hasNext();)
                {
                    DataColumnReportEx columnEx = (DataColumnReportEx) iterator.next();
                    if (!(ModelFieldTypeEnum.计算列.toString().equals(columnEx.getFieldType())
                            || ModelFieldTypeEnum.列维度指标.toString().equals(columnEx.getFieldType())))
                    {
                        iterator.remove();
                    }
                }
            }
        }
    }
    
    /**
     * 查找实现
     * @param parent 父亲列
     * @param result
     * @param parentHeader  父亲头节点
     * @param headerConfigs
     * @throws Exception
     */
    private void lookForXCommonOrCalOrGroupFieldImpl(DataColumnReportEx parent, DataColumns result, ReportHeader parentHeader, List<ReportHeader> headerConfigs) throws Exception
    {
        // 分割groupName
        String groupName = this.getGroupName();
        String fieldDataSql = this.getFieldDataSql();
        Assert.isNotNullOrEmpty(groupName, "维度名称为空，维度列信息不合法！");
        Assert.isNotNullOrEmpty(fieldDataSql, "维度数据SQL为空，维度列信息不合法！");
        String[] groupNameArr = CoreUtil.split(groupName, FieldConsts.LEVELONESPLIT);
        String[] groupDataArr = CoreUtil.split(fieldDataSql, FieldConsts.LEVELONESPLIT);
        if (groupDataArr.length != groupDataArr.length)
        {
            throw new Exception("维度名称和维度数据SQL个数不一致，维度列信息不合法！");
        }
        // 添加的维度列
        DataColumnReportEx column  = null;
        // 添加的表头
        ReportHeader headerConfig = null;
        // 条件
        List<ConditionInfo> conditions = null;
        StringBuilder builder = new StringBuilder();
        
        for (int i = 0; i < groupNameArr.length; i++)
        {
            builder.setLength(0);
            String singleLabel = groupNameArr[i];
            String singleName = CoreUtil.newShortUuId();
            
            conditions = new ArrayList<ConditionInfo>();
            // 切割条件
            String singleGroupCondition = groupDataArr[i];
            column = this.toDataColumnReportEx();
            if (parent != null)
            {
                // 父亲不显示，则子也不显示
                if (!parent.isDisplay())
                {
                    column.setDisplay(parent.isDisplay());
                }
                // 继承父的条件
                conditions.addAll(parent.getConditions());
                builder = new StringBuilder();
                builder.append(parent.getColumnLable()).append(ExcelHtmlUtil.REPLACEPOINTFLAG).append(singleLabel);
                column.setColumnLable(builder.toString());
                
                builder.setLength(0);
                builder.append(parent.getColumnName()).append(ExcelHtmlUtil.REPLACEPOINTFLAG).append(singleName);
                column.setColumnName(builder.toString());
                
                // 创建表头
                headerConfig = column.toHeaderConfig();
                // headerConfig只要显示名
                headerConfig.setDisplayName(singleLabel);
                headerConfig.setParent(parentHeader);
                // 深度加1
                headerConfig.setDeepLength(parentHeader.getDeepLength() + 1);
            } else
            {
                column.setColumnLable(singleLabel);
                column.setColumnName(singleName);
                
                // 创建表头
                headerConfig = column.toHeaderConfig();
            }
            column.setConditions(conditions);
            column.setHeaderConfig(headerConfig);
            headerConfigs.add(headerConfig);
            
            // 需要考虑这三者的添加顺序
            List<AnalyseFactorInfo> allFactorInfos = getAndSortAllAnalyseFactorInfo();
            boolean hasAddColumn = false;
            for (AnalyseFactorInfo analyseFactorInfo : allFactorInfos)
            {
                if (analyseFactorInfo instanceof QuotaInfo)
                {
                    QuotaInfo quotaInfo = (QuotaInfo)analyseFactorInfo;
                    if (ModelFieldTypeEnum.列维度指标.toString().equals(quotaInfo.getFieldType()))
                    {
                        // 如果其下面有列维度指标则添加进去
                        addColumnFields(quotaInfo, conditions, column, result, headerConfig);
                    } else if (ModelFieldTypeEnum.计算列.toString().equals(quotaInfo.getFieldType()))
                    {
                        // 如果其下有计算列则添加进去
                        addCalFields(quotaInfo, conditions, column, result, headerConfig);
                    }
                } else if (analyseFactorInfo instanceof DimensionInfo)
                {
                    // 添加一个非表头记住该位置
                    headerConfig.getChildren().add(ReportHeader.NAH);
                    // 给子维度去循环，但是只能添加一次
                    if (!hasAddColumn)
                    {
                        result.add(column);
                        hasAddColumn = true;
                    }
                }
            }
            // 没有子维度导致没有添加进去的情况需要考虑
            if (!hasAddColumn)
            {
                result.add(column);
            }
            // 维度内部仍然存在分割
            String[] groupConditionArr = CoreUtil.split(singleGroupCondition, FieldConsts.LEVELTWOSPLIT);
            if (groupConditionArr == null || groupConditionArr.length == 0)
            {
                continue;
            }
            boolean complex = groupConditionArr.length > 1;
            for (String groupCondition : groupConditionArr)
            {
                String relation = ModelUtil.getRelationSplit(groupCondition);
                // 常量维度的关系可以为空,但是也要加上去
                if (isConstant() && CoreUtil.isEmpty(relation))
                {
                    relation = FieldConsts.EQ;
                } else if (!isConstant() && CoreUtil.isEmpty(relation))
                {
                    continue;
                }
                String[] relationArr = CoreUtil.split(groupCondition, relation);
                if (relationArr.length < 1)
                {
                    continue;
                }
                // 注意常量维度不需要参与校验
                ConditionInfo conditionInfo = new ConditionInfo(isConstant() ? null : relationArr[0], this.getDataType(),
                            isConstant() ? null : relation, isConstant() ? null : relationArr[1], this.isExpType(), this.getFieldName(), headerConfig);
                conditionInfo.setDimensionDisplayName(singleLabel);
                conditionInfo.setComplex(complex);
                // 默认移动步骤为零
                conditions.add(conditionInfo);
            }
        }
        if (parentHeader != null)
        {
            // 在HeaderConfig.NAH处加
            int index = -1;
            boolean found = false;
            for (HeaderConfig heConfig : parentHeader.getChildren())
            {
                index ++;
                if (ReportHeader.NAH == heConfig)
                {
                    found = true;
                    break;
                }
            }
            // 没有找到
            if (!found)
            {
                parentHeader.getChildren().addAll(headerConfigs);
            } else
            {
                parentHeader.getChildren().remove(index);
                parentHeader.getChildren().addAll(index, headerConfigs);
            }
        }
    }

    /**
     * 获取该维度下的所有分析因子并排序
     * @return
     */
    private List<AnalyseFactorInfo> getAndSortAllAnalyseFactorInfo()
    {
        List<AnalyseFactorInfo> result = new ArrayList<AnalyseFactorInfo>();
        if (this.getChildren() != null && this.getChildren().size() > 0)
        {
            result.addAll(this.getChildren());
        }
        if (this.hasCalCol())
        {
            result.addAll(this.getCalFields());
        }
        if (this.hasColCol())
        {
            result.addAll(this.getColumnFields());
        }
        // 对分析因子排序
        Collections.sort(result, new Comparator<AnalyseFactorInfo>()
        {
            @Override
            public int compare(AnalyseFactorInfo paramT1, AnalyseFactorInfo paramT2)
            {
                return CoreUtil.compareNumber(paramT1.getFieldOrder(), paramT2.getFieldOrder());
            }
        });
        return result;
    }

    /**
     * 添加计算列
     * @param field
     * @param conditions
     * @param parent
     * @param result
     * @param parentHeader
     * @throws Exception
     */
    private void addCalFields(QuotaInfo field, List<ConditionInfo> conditions, DataColumnReportEx parent, DataColumns result, ReportHeader parentHeader) throws Exception
    {
        if (!this.hasCalCol())
        {
            return;
        }
        Assert.isNotNull(parent, "添加计算列时父节点信息为空！");
        Assert.isNotNull(parentHeader, "添加计算列时父节点信息为空！");
        // 添加的表头
        StringBuilder builder = new StringBuilder();
        // 添加的计算列
        DataColumnReportEx calColumn = field.toDataColumnReportEx();
        // 父亲不显示，则子也不显示
        if (!parent.isDisplay())
        {
            calColumn.setDisplay(parent.isDisplay());
        }
        // 设置条件(不起作用。为了生存图表)
        calColumn.setConditions(conditions);
        
        builder.setLength(0);
        builder.append(parent.getColumnName()).append(ExcelHtmlUtil.REPLACEPOINTFLAG).append(calColumn.getColumnName());
        calColumn.setColumnName(builder.toString());
        builder.setLength(0);
        builder.append(parent.getColumnLable()).append(ExcelHtmlUtil.REPLACEPOINTFLAG).append(calColumn.getColumnLable());
        calColumn.setColumnLable(builder.toString());
        
        // 计算列的FieldDataSql需要拼接上所有父级的数据
        // cb 2017 09 13 修改为最后处理计算列的datasql
        // ModelUtil.handleCalColumnFieldSql(parent.getColumnLable(), result, calColumn);
        
        // 创建表头
        ReportHeader headerConfig = calColumn.toHeaderConfig();
        // headerConfig只要显示名
        headerConfig.setDisplayName(field.getFieldName());
        headerConfig.setParent(parentHeader);
        // 深度加1
        headerConfig.setDeepLength(parentHeader.getDeepLength() + 1);
        // 加入
        result.add(calColumn);
        calColumn.setHeaderConfig(headerConfig);
        parentHeader.getChildren().add(headerConfig);
    }

    /**
     * 添加列维度指标
     * @param modelField
     * @param conditions
     * @param parent
     * @param result
     * @param parentHeader
     * @param headerConfigs
     * @throws Exception
     */
    private void addColumnFields(QuotaInfo modelField, List<ConditionInfo> conditions, DataColumnReportEx parent, DataColumns result, ReportHeader parentHeader) throws Exception
    {
        if (!this.hasColCol())
        {
            return;
        }
        Assert.isNotNull(parent, "添加列维度指标时父节点信息为空！");
        Assert.isNotNull(parentHeader, "添加列维度指标时父节点信息为空！");
        // 添加的表头
        StringBuilder builder = new StringBuilder();
        // 添加的维度指标列
        DataColumnReportEx newcolumnEx = modelField.toDataColumnReportEx();
        // 父亲不显示，则子也不显示
        if (!parent.isDisplay())
        {
            newcolumnEx.setDisplay(false);
        }
        // 设置条件
        newcolumnEx.setConditions(conditions);
        // 更换ColumnName
        builder.setLength(0);
        builder.append(parent.getColumnName()).append(ExcelHtmlUtil.REPLACEPOINTFLAG).append(newcolumnEx.getColumnName());
        newcolumnEx.setColumnName(builder.toString());
        // 更换ColumnLable
        builder.setLength(0);
        builder.append(parent.getColumnLable()).append(ExcelHtmlUtil.REPLACEPOINTFLAG).append(newcolumnEx.getColumnLable());
        newcolumnEx.setColumnLable(builder.toString());
        
        // 创建表头
        ReportHeader headerConfig = newcolumnEx.toHeaderConfig();
        // headerConfig只要显示名
        headerConfig.setDisplayName(modelField.getFieldName());
        headerConfig.setParent(parentHeader);
        // 深度加1
        headerConfig.setDeepLength(parentHeader.getDeepLength() + 1);
        // 加入
        result.add(newcolumnEx);
        
        // 20180112 如果是单指标维度，则不形成多表头
        if (isSingleQuota())
        {
            newcolumnEx.setHeaderConfig(parentHeader);
            // 拷贝这么多属性
            parentHeader.setFieldType(headerConfig.getFieldType());
            parentHeader.setFieldUnit(headerConfig.getFieldUnit());
            parentHeader.setValue(headerConfig.getValue());
        } else
        {
            newcolumnEx.setHeaderConfig(headerConfig);
            parentHeader.getChildren().add(headerConfig);
        }
    }

    /**
     * 将自身信息转成DataColumnReportEx
     * @return
     * @throws Exception 
     */
    public DataColumnReportEx toDataColumnReportEx() throws Exception
    {
        // 如果该列是在维度下面。需要拼接维度信息，并且拼接条件
        DataColumnReportEx result = new DataColumnReportEx();
        result.setFieldName(this.getFieldName());
        result.setColumnLable(this.getFieldName());
        result.setColumnName(CoreUtil.newShortUuId());
        // 计算式
        result.setFieldDataSql(this.getFieldDataSql());
        result.setExpType(this.isExpType());
        result.setDataType(this.getDataType());
        result.setFieldUnit(this.getFieldUnit());
        result.setShowOrder(this.getFieldOrder());
        
        result.setDisplay(this.isDisplay());
        return result;
    }

    public String getGroupName()
    {
        return groupName;
    }

    public String getGroupDataSql()
    {
        return groupDataSql;
    }

    public void setGroupDataSql(String groupDataSql)
    {
        this.groupDataSql = groupDataSql;
    }

    public void setGroupName(String groupName)
    {
        this.groupName = groupName;
    }

    public int getDeepLength()
    {
        return deepLength;
    }

    public void setDeepLength(int deepLength)
    {
        this.deepLength = deepLength;
    }

    public boolean isConstant()
    {
        return constant;
    }

    public void setConstant(boolean constant)
    {
        this.constant = constant;
    }

    @Override
    public boolean isLeaf()
    {
        return this.children == null || this.children.isEmpty();
    }
    
    /**
     * 是否是单指标的维度：只存在一个列维度指标
     * @return
     */
    public boolean isSingleQuota()
    {
        return !CoreUtil.isEmpty(columnFields) && columnFields.size() == 1 && CoreUtil.isEmpty(children) && CoreUtil.isEmpty(calFields);
    }
    
    /**
     * 是否级联更新子集
     * @param tempModel
     * @param casChild
     */
    public void setModel(DataAnalyseModel tempModel, boolean casChild)
    {
        this.setModel(tempModel);
        if (this.getChildren() != null && casChild)
        {
            for (DimensionInfo dimensionInfo : this.getChildren())
            {
                dimensionInfo.setModel(tempModel, casChild);
            }
        }
        if (this.getCalFields() != null)
        {
            for (QuotaInfo quotaInfo : this.getCalFields())
            {
                quotaInfo.setModel(tempModel);
            }
        }
        if (this.getColumnFields() != null)
        {
            for (QuotaInfo quotaInfo : this.getColumnFields())
            {
                quotaInfo.setModel(tempModel);
            }
        }
    }

    
}
